/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "cJSON.h"
#include "iot_cloud.h"
#include "iot_demo_def.h"
#include "iot_main.h"
#include "iot_netcfg.h"
#include "iot_profile.h"
#include "iot_sntp.h"
#include "iot_wifi.h"
#include "kv_store.h"
#include "network_config_service.h"
#include "ohos_init.h"

#include <time.h>
#include <sys/time.h>
#include <cmsis_os2.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SID_KEY "ssid"
#define PWD_KEY "password"

#define SOFTAP_NAME "teamX-DoorBell01"

#define UI_PROFILE_KEY_BEEP_STS "Beep"
#define UI_PROFILE_KEY_DOOR_BELL_STS "DoorBellStatus"

// DEFAULT PARAM, AND MUST BE MODIFIED TO THE REAL PARAMS
#define CONFIG_CLOUD_DEFAULT_SERVERIP "121.36.42.100" // replace it with iotplatform server ip
#define CONFIG_CLOUD_DEFAULT_SERVERPORT "1883"        // replace it with iotplatform server  port
#define CONFIG_SENSOR_SAMPLE_CYCLE 1000               // unit:minisecond
#define CONFIG_IR_COUNTER_CYCLE 1000                  // unit:minisecond
#define CONFIG_IR_TRIGGER_TIME_THRESHOLD 5            // unit:second
#define CONFIG_LOCK_OPEN_COUNT_TIME 5                 // unit:second
#define CONFIG_TASK_DEFAULT_STACKSIZE 0x1000          // unit:bytes
#define CONFIG_TASK_MAIN_STACKSIZE 0x2000             // main task stacksize must be bigger
#define CONFIG_TASK_DEFAULT_PRIOR 20                  // default task priority
#define CONFIG_TASK_MAIN_PRIOR 25                     // default task priority
#define CONFIG_CHN_TIMEZONE 8
#define MAIN_TASK_DELAY_TICKS 100

static SensorController g_sensorController;
static DriverController g_driverController;
static ApplicationController g_appController;

const char *g_uiDoorBellStatusMap[] = {"NO_PERSON_APPROACH", "CALLING_BELL", "UNKNOWN_PERSON_APPROACH"};
const char *g_uiDriverStatusMap[] = {"ON", "OFF"};

static void IotWifiInfo_delete(void);

static void IrStsNotice(ExtDevIrMontStsDef extDevIrMontSts)
{
    LOG_I("%s %d:Notice IR status : %d(0:EXT_DEV_IR_HAVE_MAN;1:EXT_DEV_IR_NO_MAN).", __FUNCTION__, __LINE__,
          extDevIrMontSts);
    g_sensorController.extDevIrMontSts = extDevIrMontSts;
    osEventFlagsSet(g_sensorController.sensorEvent, CN_IR_EVENT);
}
static void IrTriggerTimCb(const void *argument)
{
    (void)argument;
    g_sensorController.irTriggerSecond++;
    if (CONFIG_IR_TRIGGER_TIME_THRESHOLD < g_sensorController.irTriggerSecond) {
        osEventFlagsSet(g_sensorController.sensorEvent, CN_IR_COUNT_EVENT);
        LOG_I("%s %d:g_sensorController.sensorEvent CN_IR_COUNT_EVENT.", __FUNCTION__, __LINE__);
    }
    LOG_I("%s %d:g_sensorController.irTriggerSecond %d.", __FUNCTION__, __LINE__, g_sensorController.irTriggerSecond);
}

static void LockOpenTimCb(const void *argument)
{
    (void)argument;
    g_driverController.extDevLedAct = EXT_DEV_LED_OFF; // 使用LED模拟锁开关状态
    osEventFlagsSet(g_driverController.driverEvent, CN_LOCK_EVENT);
    LOG_I("%s %d:g_driverController.driverEvent %x.", __FUNCTION__, __LINE__, g_driverController.driverEvent);
    LOG_I("%s %d:g_driverController.extDevLedAct %d(0:EXT_DEV_LED_ON;1:EXT_DEV_LED_OFF).", __FUNCTION__, __LINE__,
          g_driverController.extDevLedAct);
}

static void KeyStsNotice(ExtDevKeyMontStsDef extDevKeyMontSts)
{
    LOG_I("%s %d:Notice key status : %d(0:EXT_DEV_KEY_UNPRESS;1:EXT_DEV_KEY_PRESSED).", __FUNCTION__, __LINE__,
          extDevKeyMontSts);
    g_sensorController.extDevKeyMontSts = extDevKeyMontSts;
    osEventFlagsSet(g_sensorController.sensorEvent, CN_KEY_EVENT);
}

/**
 * @brief Convert miniseconds to system ticks
 * @param ms Indicates the mimiseconds to convert
 * @return Returns the corresponding ticks of specified time
 */
static uint32_t Time2Tick(uint32_t ms)
{
    uint64_t ret;
    ret = ((uint64_t)ms * osKernelGetTickFreq()) / CN_MINISECONDS_IN_SECOND;
    return (uint32_t)ret;
}

static int16_t DoorBellSensorInit(void)
{
    // 申请传感器事件管理Handle
    g_sensorController.sensorEvent = osEventFlagsNew(NULL);
    if (g_sensorController.sensorEvent == NULL) {
        LOG_E("%s %d:Failed to reply sensor event.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    g_sensorController.irTriggerSecond = 0;

    // 人体感应触发计时器申请
    g_sensorController.irTriggerTimerHandle = osTimerNew(IrTriggerTimCb, osTimerPeriodic, NULL, NULL);
    if (NULL == g_sensorController.irTriggerTimerHandle) {
        LOG_E("%s %d:Failed to reply ir timer.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    // 初始化人体感应触发方式
    ExtDevIrCfgDef extDevIrCfg = {
        .extDevIrStsNoticeCb = IrStsNotice, // 通知方式
        .extDevIrWorkType = EXT_DEV_IR_NOTICE,
    };

    if (EXT_DEV_SUCCESS != ExtDevIrInit(extDevIrCfg)) {
        LOG_E("%s %d:Failed to init ir.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    g_sensorController.extDevIrMontSts = EXT_DEV_IR_NO_MAN;
    // 初始化按键检测方式
    ExtDevKeyCfgDef extDevKeyCfg = {
        .extDevKeyId = EXT_DEV_KEY_0,
        .extDevKeyWorkType = EXT_DEV_KEY_NOTICE,
        .extDevKeyStsNoticeCb = KeyStsNotice,
    };
    if (EXT_DEV_SUCCESS != ExtDevKeyInit(extDevKeyCfg)) {
        LOG_E("%s %d:Failed to init key.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    g_sensorController.extDevKeyMontSts = EXT_DEV_KEY_UNPRESS;
    g_sensorController.doorBellStatusTmp = NO_PERSON_APPROACH;
    return APP_RET_SUCCESS;
}

static void DoorBellSensorTask(const void *arg)
{
    (void)arg;

    LOG_I("%s %d:DoorBellSensorTask in! \n", __FUNCTION__, __LINE__);
    // 初始化外设
    if (APP_RET_FAILED == DoorBellSensorInit()) {
        LOG_E("%s %d:DoorBellSensorInit failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    // 循环获取传感器状态并判断当前状态
    while (1) {
        // 获取传感器状态
        uint32_t sensorEvent = osEventFlagsWait(g_sensorController.sensorEvent, CN_SENSOR_EVENT_ALL, osFlagsWaitAny,
                                                Time2Tick(CONFIG_SENSOR_SAMPLE_CYCLE));
        // 判断是否有事件需要处理
        if ((sensorEvent & CN_EVENT_ERROR) || (!(sensorEvent & CN_SENSOR_EVENT_ALL))) {
            continue;
        }
        LOG_I("%s %d:%x:CN_IR_COUNT_EVENT;%x:CN_KEY_EVENT;", __FUNCTION__, __LINE__, CN_IR_COUNT_EVENT, CN_KEY_EVENT);
        // 有事件需要处理
        if (sensorEvent & CN_IR_EVENT) { // 人体感应事件
            if (EXT_DEV_IR_HAVE_MAN == g_sensorController.extDevIrMontSts) {
                // 启动60s定时器
                if (osOK != osTimerStart(g_sensorController.irTriggerTimerHandle, Time2Tick(CONFIG_IR_COUNTER_CYCLE))) {
                    LOG_E("%s %d:irTriggerTimerHandle start error.", __FUNCTION__, __LINE__);
                }
            } else if (EXT_DEV_IR_NO_MAN == g_sensorController.extDevIrMontSts) {
                // 停止60s定时器
                if (osOK != osTimerStop(g_sensorController.irTriggerTimerHandle)) {
                    LOG_E("%s %d:irTriggerTimerHandle stop error!", __FUNCTION__, __LINE__);
                }
                g_sensorController.irTriggerSecond = 0;
            } else {
                // 不应该执行到这儿
            }
        } else { // 其它事件暂不需要处理
            // 不应该执行到这儿
        }

        // 判断当前状态
        if (EXT_DEV_KEY_PRESSED == g_sensorController.extDevKeyMontSts) { // 访客响铃
            g_sensorController.doorBellStatusTmp = CALLING_BELL;
            LOG_I("%s %d:g_sensorController.doorBellStatusTmp is CALLING_BELL", __FUNCTION__, __LINE__);
        } else if (EXT_DEV_KEY_UNPRESS == g_sensorController.extDevKeyMontSts) {
            if ((EXT_DEV_IR_HAVE_MAN == g_sensorController.extDevIrMontSts) &&
                (g_sensorController.irTriggerSecond > CONFIG_IR_TRIGGER_TIME_THRESHOLD)) { // 不明人员
                g_sensorController.doorBellStatusTmp = UNKNOWN_PERSON_APPROACH;
                LOG_I(
                    "%s %d:g_sensorController.doorBellStatusTmp is "
                    "UNKNOWN_PERSON_APPROACH",
                    __FUNCTION__, __LINE__);
            } else { // 无人
                g_sensorController.doorBellStatusTmp = NO_PERSON_APPROACH;
                LOG_I("%s %d:g_sensorController.doorBellStatusTmp is NO_PERSON_APPROACH", __FUNCTION__, __LINE__);
            }
        } else {
            // 不应该执行到这
        }
        // 状态同步及迁移判断
        if (g_sensorController.doorBellStatusTmp != g_appController.doorBellStatus) { // 状态发生变化可能需要状态迁移
            if ((CALLING_BELL != g_appController.doorBellStatus) ||
                (UNKNOWN_PERSON_APPROACH != g_sensorController.doorBellStatusTmp)) {   // 是否满足状态迁移条件
                g_appController.doorBellStatus = g_sensorController.doorBellStatusTmp; // 状态同步
                osEventFlagsSet(g_appController.appEvent, CN_APP_DOOR_BELL_STATUS_EVENT);
                LOG_I(
                    "%s %d:g_appController.doorBellStatus is "
                    "%d.(0:NO_PERSON_APPROACH;1:CALLING_BELL;2:UNKNOWN_PERSON_APPROACH;"
                    ")",
                    __FUNCTION__, __LINE__, g_appController.doorBellStatus);
                // 刷新执行器状态
                g_driverController.extDevBeepAct =
                    (NO_PERSON_APPROACH != g_appController.doorBellStatus) ? EXT_DEV_BEEP_ON : EXT_DEV_BEEP_OFF;
                // 设置相关事件
                osEventFlagsSet(g_driverController.driverEvent, CN_BEEP_EVENT);
                LOG_I(
                    "%s %d:g_driverController.extDevBeepAct is "
                    "%d.(0:EXT_DEV_BEEP_ON;1:EXT_DEV_BEEP_OFF;)",
                    __FUNCTION__, __LINE__, g_driverController.extDevBeepAct);
            }
        }
        LOG_I("%s %d:g_sensorController\r\n", __FUNCTION__, __LINE__);
        LOG_I("%s %d:.irTriggerSecond = %d\r\n", __FUNCTION__, __LINE__, g_sensorController.irTriggerSecond);
        LOG_I("%s %d:.irTriggerTimerHandle = %x\r\n", __FUNCTION__, __LINE__, g_sensorController.irTriggerTimerHandle);
        LOG_I("%s %d:.extDevIrMontSts = %d(0:EXT_DEV_IR_HAVE_MAN;1:EXT_DEV_IR_NO_MAN)\r\n", __FUNCTION__, __LINE__,
              g_sensorController.extDevIrMontSts);
        LOG_I(
            "%s %d:.doorBellStatusTmp = "
            "%d(0:NO_PERSON_APPROACH;1:CALLING_BELL;2:UNKNOWN_PERSON_APPROACH;)\r\n\t",
            __FUNCTION__, __LINE__, g_sensorController.doorBellStatusTmp);
    } // while循环到此结束
}

/************************************************
设置操作系统时间
参数:*dt数据格式为"2006-4-20 20:30:30"
调用方法:
char *pt="2006-4-20 20:30:30";
SetSystemTime(pt);
**************************************************/
static int SetSystemTime(char *dt)
{
    struct tm tm;
    static struct timeval tv;
    static time_t timep;

    LOG_I("%s %d: %s %s", __FUNCTION__, __LINE__, __DATE__, __TIME__);
    if(NULL != dt) {
        sscanf(dt, "%d-%d-%d %d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
        tm.tm_mon -= 1;
        tm.tm_year -= 1900;
    }
    else {
        if (0 != SntpGetRtcTime(CONFIG_CHN_TIMEZONE,&tm)) { 
            LOG_E("%s %d: SntpGetRtcTime failed!", __FUNCTION__, __LINE__);
            return -1;
        }
    }
    LOG_I("%s %d: %d-%d-%d %d:%d:%d", __FUNCTION__, __LINE__, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
    timep = mktime(&tm);
    tv.tv_sec = timep;
    tv.tv_usec = 0;
    if(settimeofday (&tv, NULL) < 0) {
        LOG_I("Set system datatime error!\n");
        return -1;
    }
    return 0;
}

static int16_t DoorBellControlInit(void)
{
    // 申请驱动外设事件管理Handle
    g_driverController.driverEvent = osEventFlagsNew(NULL);
    if (g_driverController.driverEvent == NULL) {
        LOG_E("%s %d:Failed to reply driver event.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    // 门锁远程开启计时器申请
    g_driverController.lockOpenTimerHandle = osTimerNew(LockOpenTimCb, osTimerOnce, NULL, NULL);
    if (NULL == g_driverController.lockOpenTimerHandle) {
        LOG_E("%s %d:Failed to reply lock open counter timer.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    // 初始化LED灯
    if (EXT_DEV_SUCCESS != ExtDevLedInit()) {
        LOG_E("%s %d:Failed to init alarm led.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    // 将蓝色LED设为报警灯,并设置初始状态
    g_driverController.extDevLedId = EXT_DEV_LED_BLUE;
    g_driverController.extDevLedAct = EXT_DEV_LED_OFF;
    // 报警蜂鸣器初始化
    if (EXT_DEV_SUCCESS != ExtDevBeepInit()) {
        LOG_E("%s %d:Failed to init beep.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    g_driverController.extDevBeepAct = EXT_DEV_BEEP_OFF;
    return APP_RET_SUCCESS;
}

static void DoorBellControlTask(const void *arg)
{
    (void)arg;
    LOG_I("%s %d:DoorBellControlTask in! \n", __FUNCTION__, __LINE__);
    // 初始化外设
    if (APP_RET_FAILED == DoorBellControlInit()) {
        LOG_E("%s %d:DoorBellControlInit failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    // 循环获取驱动设备事件通知并执行
    while (1) {
        // 获取驱动设备事件通知状态
        uint32_t driverEvent = osEventFlagsWait(g_driverController.driverEvent, CN_CONTROL_EVENT_ALL, osFlagsWaitAny,
                                                Time2Tick(CONFIG_SENSOR_SAMPLE_CYCLE));
        // 判断事件是否需要处理
        if ((driverEvent & CN_EVENT_ERROR) || (!(driverEvent & CN_CONTROL_EVENT_ALL))) {
            continue;
        }
        LOG_I("%s %d:%x:CN_BEEP_EVENT;%x:CN_LOCK_EVENT;", __FUNCTION__, __LINE__, CN_BEEP_EVENT, CN_LOCK_EVENT);
        if (driverEvent & CN_BEEP_EVENT) { // 蜂鸣器事件
            LOG_I("%s %d:g_driverController.extDevBeepAct:%d(0:EXT_DEV_BEEP_ON;1:EXT_DEV_BEEP_OFF;)", __FUNCTION__,
                  __LINE__, g_driverController.extDevBeepAct);
            if (EXT_DEV_SUCCESS != ExtDevBeepSet(g_driverController.extDevBeepAct)) {
                LOG_E("%s %d:Beep on failed!", __FUNCTION__, __LINE__);
            }
            if (EXT_DEV_BEEP_ON == g_driverController.extDevBeepAct) {
                if (EXT_DEV_SUCCESS != ExtDevLedSetBlinking(EXT_DEV_LED_RED, 1000)) {
                    LOG_E("extDevLedSetBlinking red failed!");
                }
            } else if (EXT_DEV_BEEP_OFF == g_driverController.extDevBeepAct) {
                if (EXT_DEV_SUCCESS != ExtDevLedSetSwitch(EXT_DEV_LED_RED, EXT_DEV_LED_OFF)) {
                    LOG_E("extDevLedSetSwitch red failed!");
                }
            }

            // 判断蜂鸣器状态是否需要同步
            if (g_appController.beepStatus != g_driverController.extDevBeepAct) {
                g_appController.beepStatus = g_driverController.extDevBeepAct;
                osEventFlagsSet(g_appController.appEvent, CN_APP_BEEP_EVENT);
            }
        } else if (driverEvent & CN_LOCK_EVENT) { // LED灯模拟门锁
            if (EXT_DEV_SUCCESS !=
                ExtDevLedSetSwitch(g_driverController.extDevLedId, g_driverController.extDevLedAct)) {
                LOG_E("extDevLedSetSwitch failed!");
            }
            if (EXT_DEV_LED_ON == g_driverController.extDevLedAct) {
                // 启动5s定时器
                if (osOK != osTimerStart(g_driverController.lockOpenTimerHandle,
                                         Time2Tick(CONFIG_LOCK_OPEN_COUNT_TIME * CN_MINISECONDS_IN_SECOND))) {
                    LOG_E("%s %d:lockOpenTimerHandle start error.", __FUNCTION__, __LINE__);
                }
                // 状态变化触发app事件
                g_appController.lockStatus = LOCK_OPEN;
                LOG_I("%s %d:g_appController.lockStatus = LOCK_OPEN!", __FUNCTION__, __LINE__);
            } else if (EXT_DEV_LED_OFF == g_driverController.extDevLedAct) {
                // 停止5s定时器
                if (osOK != osTimerStop(g_driverController.lockOpenTimerHandle)) {
                    LOG_E("%s %d:lockOpenTimerHandle stop error!", __FUNCTION__, __LINE__);
                }
                // 状态变化触发app事件
                g_appController.lockStatus = LOCK_CLOSE;
            } else {
                LOG_E("%s %d:Unexpect led action!", __FUNCTION__, __LINE__);
            }
            //设置门状态事件
            osEventFlagsSet(g_appController.appEvent, CN_APP_LOCK_EVENT);
            LOG_I("%s %d:osEventFlagsSet CN_LOCK_EVENT\r\n", __FUNCTION__, __LINE__);
        } else { // 其它事件暂不需要处理
            // 不应该执行到这儿
        }
        LOG_I("%s %d:g_driverController\r\n", __FUNCTION__, __LINE__);
        LOG_I("%s %d:.extDevLedAct = %d\r\n", __FUNCTION__, __LINE__, g_driverController.extDevLedAct);
        LOG_I("%s %d:.extDevBeepAct = %d\r\n", __FUNCTION__, __LINE__, g_driverController.extDevBeepAct);
    }
}

static int JsGetClang(const char *key, char *value)
{
    int ret = -1;
    char *retString = NULL;
    cJSON *rootObj;
    cJSON *doorBellStatus;
    cJSON *beepStatus;

    // build a rootObj node
    rootObj = cJSON_CreateObject();
    if (NULL == rootObj) {
        LOG_E("%s %d: cJSON_CreateObject \n", __FUNCTION__, __LINE__);
        goto MAKE_JSON_ERR;
    }
    // add the DoorBellStatus to the rootObj node
    doorBellStatus = cJSON_CreateString(g_uiDoorBellStatusMap[g_appController.doorBellStatus]);
    if (NULL == doorBellStatus) {
        LOG_E("%s %d: cJSON_CreateString %s\n", __FUNCTION__, __LINE__,
              g_uiDoorBellStatusMap[g_appController.doorBellStatus]);
        goto MAKE_JSON_ERR;
    }
    cJSON_AddItemToObjectCS(rootObj, UI_PROFILE_KEY_DOOR_BELL_STS, doorBellStatus);

    beepStatus = cJSON_CreateString(g_uiDriverStatusMap[g_appController.beepStatus]);
    if (NULL == beepStatus) {
        LOG_E("%s %d: cJSON_CreateString %s\n", __FUNCTION__, __LINE__,
              g_uiDriverStatusMap[g_appController.beepStatus]);
        goto MAKE_JSON_ERR;
    }
    cJSON_AddItemToObjectCS(rootObj, UI_PROFILE_KEY_BEEP_STS, beepStatus);

    retString = cJSON_PrintUnformatted(rootObj);
    if(NULL != retString) {
        memcpy(value, retString, strlen(retString) + 1);
        cJSON_free(retString);
    }
    cJSON_Delete(rootObj);
    // LOG_I("%s %d: value %s", __FUNCTION__, __LINE__, value);
    return 0;
MAKE_JSON_ERR:
    if (rootObj) {
        cJSON_Delete(rootObj);
    }
    return -1;
}

static int JsSetClang(const char *key, char *value)
{
    cJSON *objPara = NULL;

    if (NULL == key || NULL == value) {
        RaiseLog(LOG_LEVEL_ERR, "NULL POINT!\n");
        return -1;
    }
    if (0 == strcmp(key, "Beep")) {
        g_driverController.extDevBeepAct = (0 == strcmp(value, "ON")) ? EXT_DEV_BEEP_ON : EXT_DEV_BEEP_OFF;
        osEventFlagsSet(g_driverController.driverEvent, CN_BEEP_EVENT);
    } else if (0 == strcmp(key, "SET_BIND")) {
        if (0 == strcmp(value, "SOFT_AP")) {
            IotWifiInfo_delete();
            LOG_I("%s %d: Bind type is [softap],please reset!\n", __FUNCTION__, __LINE__);
        }
    } else {
        LOG_E("%s %d: Unexpect set [%s]-[%s]", __FUNCTION__, __LINE__, key, value);
        return -1;
    }
    return 0;
}

static void DoorBellStart(void)
{
    osThreadAttr_t attr;
    LOG_I("%s %d:DoorBellStart start", __FUNCTION__, __LINE__);
    // 创建门铃传感器Task
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CONFIG_TASK_DEFAULT_STACKSIZE;
    attr.priority = CONFIG_TASK_DEFAULT_PRIOR;
    attr.name = "DoorBellSensor";
    if (osThreadNew((osThreadFunc_t)DoorBellSensorTask, NULL, (const osThreadAttr_t *)&attr) == NULL) {
        return;
    }

    LOG_I("%s %d:DoorBellSensorTask start ok", __FUNCTION__, __LINE__);
    // 创建门铃传感器Task
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CONFIG_TASK_DEFAULT_STACKSIZE;
    attr.priority = CONFIG_TASK_DEFAULT_PRIOR;
    attr.name = "DoorBellControl";
    if (osThreadNew((osThreadFunc_t)DoorBellControlTask, NULL, (const osThreadAttr_t *)&attr) == NULL) {
        return;
    }
    LOG_I("%s %d:DoorBellControlTask start ok", __FUNCTION__, __LINE__);
    JsGetClangFuncationRegister(JsGetClang);

    JsSetClangFuncationRegister(JsSetClang);

    return;
}

static int IotWifiInfo_get(char *ssid, int id_size, char *pwd, int pd_size)
{
    if (UtilsSetEnv("/data/") != 0) {
        LOG_E("%s %d:store ssid failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    int retval = UtilsGetValue(SID_KEY, ssid, id_size);
    if (retval <= 0) {
        LOG_E("%s %d:no such ssid stored! \n", __FUNCTION__, __LINE__);
        return 0;
    }

    if (UtilsGetValue(PWD_KEY, pwd, pd_size) < 0) {
        LOG_E("%s %d:ssid(%s) no password stored! \n", __FUNCTION__, __LINE__, ssid);
    } else {
        LOG_E("%s %d:ssid : %s, pwd : %s! \n", __FUNCTION__, __LINE__, ssid, pwd);
    }

    return 1;
}

static void IotWifiInfo_set(char *ssid, char *pwd)
{
    if (UtilsSetEnv("/data/") != 0) {
        LOG_E("%s %d:store ssid failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    if (UtilsSetValue(SID_KEY, ssid) != 0) {
        LOG_E("%s %d:store ssid failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    if (UtilsSetValue(PWD_KEY, pwd) != 0) {
        LOG_E("%s %d:store password failed! \n", __FUNCTION__, __LINE__);
        UtilsDeleteValue(SID_KEY);
        return;
    }
    LOG_I("%s %d:store password success! \n", __FUNCTION__, __LINE__);
}

static void IotWifiInfo_delete(void)
{
    if (UtilsSetEnv("/data/") != 0) {
        LOG_E("%s %d:store ssid failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    if (UtilsDeleteValue(SID_KEY) != 0) {
        LOG_E("%s %d:delete ssid failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    if (UtilsDeleteValue(PWD_KEY) != 0) {
        LOG_E("%s %d:delete password failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    LOG_I("%s %d:delete ssid password success! \n", __FUNCTION__, __LINE__);
}

static int16_t DoorBellAppInit(void)
{
    // 申请驱动外设事件管理Handle
    g_appController.appEvent = osEventFlagsNew(NULL);
    if (g_appController.appEvent == NULL) {
        LOG_E("%s %d:Failed to reply app event.", __FUNCTION__, __LINE__);
        return APP_RET_FAILED;
    }
    g_appController.wifiStatus = WIFI_ST_NOT_BIND;
    g_appController.lockStatus = LOCK_CLOSE;
    g_appController.beepStatus = EXT_DEV_BEEP_OFF;
    g_appController.doorBellStatus = NO_PERSON_APPROACH;
    return APP_RET_SUCCESS;
}
static void DoorBellAppTask(const void *arg)
{
    (void)arg;
    int32_t reportIntervalCount = 0;
    // 初始化外设
    if (APP_RET_FAILED == DoorBellAppInit()) {
        LOG_E("%s %d:DoorBellAppInit failed! \n", __FUNCTION__, __LINE__);
        return;
    }
    // app while 循环
    while (1) {
        uint32_t appEvent = osEventFlagsWait(g_appController.appEvent, CN_APP_EVENT_ALL, osFlagsWaitAny,
                                             Time2Tick(CONFIG_SENSOR_SAMPLE_CYCLE));
        // 1.判断是否需要上报报警信息
        if ((!(appEvent & CN_EVENT_ERROR)) && (appEvent & CN_APP_DOOR_BELL_STATUS_EVENT)) {
            if (CALLING_BELL == g_appController.doorBellStatus) {
                if (0 != CLOUD_ReportNotification(NOTIFY_TYPE_NORMAL, "Calling bell", "访客唤铃")) {
                    LOG_E("CLOUD_ReportNotification error!");
                }
                LOG_I("%s %d:Calling bell Notice!", __FUNCTION__, __LINE__);
            } else if (UNKNOWN_PERSON_APPROACH == g_appController.doorBellStatus) {
                if (0 != CLOUD_ReportNotification(NOTIFY_TYPE_URGENT, "UNKNOWN person staying", "不明人员逗留")) {
                    LOG_E("CLOUD_ReportNotification error!");
                }
                LOG_I("%s %d:UNKNOWN person staying warning!", __FUNCTION__, __LINE__);
            } else {
                // 无人靠近或其他未定义的状态不需要处理
                LOG_I("%s %d:no person approach recover!", __FUNCTION__, __LINE__);
            }
        }
        // 2.判断是否需要上报状态信息
        if (reportIntervalCount < 5) {
            // 判断事件是否需要处理
            if ((appEvent & CN_EVENT_ERROR) || (!(appEvent & CN_APP_EVENT_ALL))) {
                reportIntervalCount++;
                LOG_I("%s %d:reportIntervalCount %d.", __FUNCTION__, __LINE__, reportIntervalCount);
                continue;
            }
        }
        // 上报本地数据
        LOG_I("%s %d:IotProfile_Report:", __FUNCTION__, __LINE__);
        LOG_I("%s %d:doorBellStatus:%d.(0:NO_PERSON_APPROACH;1:CALLING_BELL;2:UNKNOWN_PERSON_APPROACH;)", __FUNCTION__,
              __LINE__, g_appController.doorBellStatus);
        LOG_I("%s %d:lockStatus:%d.(0:LOCK_OPEN;1:LOCK_CLOSE;)", __FUNCTION__, __LINE__, g_appController.lockStatus);
        LOG_I("%s %d:beepStatus:%d.(0:EXT_DEV_BEEP_ON;1:EXT_DEV_BEEP_OFF;)", __FUNCTION__, __LINE__,
              g_appController.beepStatus);
        if (0 !=
            IotProfile_Report(g_appController.doorBellStatus, g_appController.lockStatus, g_appController.beepStatus)) {
            LOG_E("IotProfile_Report error!");
        }
        reportIntervalCount = 0;
    }
    return;
}

int IotProfile_CommandCallback(int command, void *cmdParam)
{
    CommandParamSetBeep *paramSetBeep;
    CommandParamSetLock *paramSetLock;
    if (NULL == cmdParam) {
        LOG_I("cmdParam is NULL!");
        return -1;
    }
    switch (command) {
        case CLOUD_COMMAND_SET_BEEP:
            paramSetBeep = (CommandParamSetBeep *)cmdParam;
            LOG_I("CLOUD_COMMAND_SET_BEEP %d", paramSetBeep->status);
            g_driverController.extDevBeepAct = paramSetBeep->status ? EXT_DEV_BEEP_ON : EXT_DEV_BEEP_OFF;
            osEventFlagsSet(g_driverController.driverEvent, CN_BEEP_EVENT);
            break;
        case CLOUD_COMMAND_SET_LOCK:
            paramSetLock = (CommandParamSetLock *)cmdParam;
            LOG_I("CLOUD_COMMAND_SET_LOCK %d", paramSetLock->status);
            g_driverController.extDevLedAct = paramSetLock->status ? EXT_DEV_LED_ON : EXT_DEV_LED_OFF;
            osEventFlagsSet(g_driverController.driverEvent, CN_LOCK_EVENT);
            break;
        default:
            LOG_I("Unexpect command %d.", command);
            break;
    }
    return 0;
}

static void DoorBellIotTask(const void *arg)
{
    int ret;
    char pwd[BUFF_SIZE] = {0};
    char ssid[BUFF_SIZE] = {0};

    // 获取路由信息
    ret = IotWifiInfo_get(ssid, BUFF_SIZE, pwd, BUFF_SIZE);
    LOG_I("%s %d:IotWifiInfo_get ret %d.", __FUNCTION__, __LINE__, ret);
    if (0 == ret) { // 未查找到路由信息，进行配网
        LOG_I("%s %d:BOARD_NetCfgStartConfig! \n", __FUNCTION__, __LINE__);
        if (BOARD_NetCfgStartConfig(SOFTAP_NAME, ssid, sizeof(ssid), pwd, sizeof(pwd)) < 0) {
            LOG_E("%s %d:BOARD_NetCfgStartConfig failed! \n", __FUNCTION__, __LINE__);
            return;
        }
    }
    // 连接WiFi
    ret = BOARD_ConnectWifi(ssid, pwd);
    if (0 != ret) {
        LOG_E("%s %d:ConnectWifi failed, retry.", __FUNCTION__, __LINE__);
    } else {
        g_appController.wifiStatus = WIFI_SIGNAL_LEVEL_1;
        // 联网成功，储存路由信息
        IotWifiInfo_set(ssid, pwd);
        // 同步网络时间
        SetSystemTime(NULL);
        // 联网成功，云通信初始化
        LOG_I("%s %d:CLOUD_Init", __FUNCTION__, __LINE__);
        if (CLOUD_Init() != 0) {
            LOG_E("%s %d:CLOUD_Init failed, return.", __FUNCTION__, __LINE__);
        } else { // 云通信初始化成功，连接云平台
            char devicePWD[] = "12345678";
            char deviceID[] = "61ba9cdd2b2aa20288c4f58a_DoorBell01";
            if (CLOUD_Connect(deviceID, devicePWD, CONFIG_CLOUD_DEFAULT_SERVERIP, CONFIG_CLOUD_DEFAULT_SERVERPORT) !=
                0) {
                LOG_E("%s %d:CLOUD_Connect failed, return.", __FUNCTION__, __LINE__);
            }
            osThreadAttr_t attr;
            // Create the IoT Main task
            attr.attr_bits = 0U;
            attr.cb_mem = NULL;
            attr.cb_size = 0U;
            attr.stack_mem = NULL;
            attr.stack_size = CONFIG_TASK_MAIN_STACKSIZE;
            attr.priority = CONFIG_TASK_MAIN_PRIOR;
            attr.name = "IoT";
            osThreadNew((osThreadFunc_t)DoorBellAppTask, NULL, (const osThreadAttr_t *)&attr);
        }
        extern void os_heap_stat_print(void);
        while(1) {
            int wifiStatus = BOARD_GetWifiSignalLevel();
            LOG_I("WiFi Signal level is %d.\r\n", wifiStatus);
            os_heap_stat_print();
            osDelay(1000 * 2);
        }
    }
    return;
}

static void IotStart(void)
{
    osThreadAttr_t attr;
    // Create the IoT Main task
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CONFIG_TASK_MAIN_STACKSIZE;
    attr.priority = CONFIG_TASK_MAIN_PRIOR;
    attr.name = "IoT";
    (void)osThreadNew((osThreadFunc_t)DoorBellIotTask, NULL, (const osThreadAttr_t *)&attr);
}

static void IotMainTaskEntry(const void *arg)
{
    // 门铃
    DoorBellStart();
    // 云通信
    IotStart();
    return;
}

/**
 * @brief IoT Main Entry of the IoT-Flower project
 */
static void IotMainEntry(void)
{
    osThreadAttr_t attr;
    RaiseLog(LOG_LEVEL_INFO, "DATA:%s Time:%s \r\n", __FUNCTION__, __DATE__, __TIME__);
    // Create the IoT Main task
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CONFIG_TASK_MAIN_STACKSIZE;
    attr.priority = CONFIG_TASK_MAIN_PRIOR;
    attr.name = "IoTMain";
    (void)osThreadNew((osThreadFunc_t)IotMainTaskEntry, NULL, (const osThreadAttr_t *)&attr);

    return;
}
// Add the IotMainEntry function to the System Startup Procedure
APP_FEATURE_INIT(IotMainEntry);